<?php defined('SYSPATH') OR die('No direct access allowed.');
/**
 * Naked objects Php controller. 
 * 
 * This implements a generic controller for a CRUD GUI for direct access to models.
 * The URL format is:
 * /nop/{model_name}/{method}[/other/arguments/etc]
 * 
 * model_name is used to load the model class.  Method is the method the call on that class.  Any other arguments 
 * required by the method are taken from the following segments.  If there is an additional method argument beyond
 * what is on the url, and there is POST information, then the raw POST data is given to this argument.
 *
 * @author     Aric Caley
 * @copyright  (c) 2009 
 */
class Nop_Controller extends CalAmpTemplate_Controller {
    // Set the name of the template to use
    public $template = 'template';

    public function __call($nop, $arguments)
    {  
        $data = null;
        
        //** Determine the appropriate object based on what is being requested (url:  nop/object/method)
        $nop_class = ucfirst($nop) . "_Model";

        //** instantiate the object
        $obj = new $nop_class();
        
        //** get the method being called
        if (isset($arguments[0])) {
            $action = ucfirst($arguments[0]);
            array_shift($arguments);
        }
        else $action = 'View';

        //** determine what kind of output trait to compose into our object
        if (request::is_ajax() AND 'json' == request::preferred_accept(array('json'))) {
            //** Add the JSON trait to our object
            Trait::uses($nop_class, 'Nop_Json');
        }
        else {
            //** Add the HTML trait to our object
            Trait::uses($nop_class, 'Nop_Html');
        }
        
        //** reflect on the method being called to see how many arguments it wants
        $method_reflect = new ReflectionAnnotatedMethod($nop_class, $action);
        //** expecting more data from a POST?
        if (sizeof($arguments) == $method_reflect->getNumberOfRequiredParameters()-1) {
            if ('post' == request::method()) {
                $data = file_get_contents("php://input");
                if (!$data) throw new Exception("No data posted");
            }
            else throw new Exception("Missing argument for $nop_class::$action");
        }

        //** if this is an ajax (xmlhttprequest) request then just send JSON data (and only accept JSON)
        if (request::is_ajax()) {
            if ('post' == request::method()) {
                $data = json_decode($data,true);
                if (NULL == $data OR is_string($data)) throw new Exception("Badly formatted JSON data");
            }
            
            //** are they asking for json data?  (jquery:  $.getJSON() )
            if ('json' == request::preferred_accept(array('json'))) {
                $this->Header();
                
                if (is_array($data) AND ($err = $obj->ValidateData($data)) != null) {
                    $this->result["ValidateError"] = $err;
                }
                else {
                    $arguments[] = $data;
                    $this->result[$nop] = $method_reflect->invokeArgs($obj, $arguments);
                }
                
                echo json_encode($this->result);
            }
            else {
                $arguments[] = $data;
                echo $method_reflect->invokeArgs($obj, $arguments);
            }

            $this->auto_render = FALSE;
        }
        //** else just send generic html
        else {
            if ('post' == request::method()) { 
                $data = $this->input->post();
            }

            if (is_array($data) AND ($err = $obj->ValidateData($data)) != null) {
                $this->template->content = "ValidateError = " . implode(", ", $err);
            }
            else {
                $arguments[] = $data;
                $this->template->content = $method_reflect->invokeArgs($obj, $arguments);
            }
        }            
    }
}